package cn.edu.jxau.core.web;

import cn.edu.jxau.core.ApplicationContext;
import cn.edu.jxau.core.Constant;
import cn.edu.jxau.core.util.JsonUtils;
import cn.edu.jxau.core.util.ReflectUtils;
import cn.edu.jxau.core.util.UploadUtils;
import org.apache.commons.fileupload.FileUploadException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

/**
 * Desc:
 * ------------------------------------
 * Author:fulei04@meituan.com
 * Date:2017/12/17
 * Time:下午2:52
 */
@WebServlet(urlPatterns = "/*", loadOnStartup = 0)
public class DispatcherServlet extends HttpServlet {

    private Dispatcher dispatcher = new Dispatcher();

    @Override
    public void init(ServletConfig servletConfig) {

        ServletContext servletContext = servletConfig.getServletContext();
        ServletRegistration jspServlet = servletContext.getServletRegistration("jsp"); //jsp资源转发
        jspServlet.addMapping(Constant.JSP_BASE_PATH + "*");
        ServletRegistration defaultServlet = servletContext.getServletRegistration("default"); //静态资源转发
        defaultServlet.addMapping(Constant.ASSET_BASE_PATH + "*");

        UploadUtils.init(servletContext); //文件上传初始化
    }

    /**
     * @param request
     * @param response
     */
    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {

        // 根据请求获取Handler //
        Handler handler = getHandlerByRequest(request);

        // 封装请求参数 //
        Param param = null;
        try {
            param = getParamByRequest(request);
        } catch (FileUploadException e) {
            throw new RuntimeException("文件上传失败",e);
        }

        // 处理请求并响应 //
        handle(request, response, handler, param);
    }

    private Handler getHandlerByRequest(HttpServletRequest request) {

        String requestMethod = request.getMethod();
        String requestURL = request.getRequestURI();
        System.out.println("------------------------------------------");
        System.out.println("---\t" + requestMethod + ":" + requestURL);
        System.out.println("------------------------------------------\n");
        return dispatcher.getHandler(requestMethod.toUpperCase(), requestURL);
    }

    private Param getParamByRequest(HttpServletRequest request) throws IOException, FileUploadException {

        if(UploadUtils.isMultipart(request)) { //文件上传特殊处理
            return UploadUtils.getParam(request);
        } else {
            List<FormFieldParam> formFieldParam = new ArrayList<>();
            Enumeration<String> enumeration = request.getParameterNames();
            while (enumeration.hasMoreElements()) {
                String name = enumeration.nextElement();
                String[] values = request.getParameterValues(name);
                formFieldParam.add(new FormFieldParam(name,values));
            }
            return new Param(formFieldParam);
        }
    }

    private void handle(HttpServletRequest request, HttpServletResponse response, Handler handler, Param param) throws IOException, ServletException {

        if (handler == null) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "未找到对应的Handler");
            return;
        }
        Method method = handler.getAction();
        Object ret = null;
        if (param.isEmpty()) {
            ret = ReflectUtils.invokeMethod(method, ApplicationContext.getBean(handler.getController()));
        } else {
            ret = ReflectUtils.invokeMethod(method, ApplicationContext.getBean(handler.getController()), param);
        }
        if (ret instanceof View) {
            returnView(request, response, (View) ret);
        } else if (ret instanceof Data) {
            returnData(response, (Data) ret);
        } else {
            //throw new IllegalStateException("不支持的action方法返回类型"); 可能为null
        }
    }

    private void returnView(HttpServletRequest request, HttpServletResponse response, View view) throws IOException, ServletException {

        String path = view.getPath();
        if (path.startsWith("/")) { //重定向
            response.sendRedirect(request.getContextPath() + path);
        } else { //转发
            for (Map.Entry<String, Object> entry : view.getModel().entrySet()) {
                request.setAttribute(entry.getKey(), entry.getValue());
            }
            request.getRequestDispatcher(Constant.JSP_BASE_PATH + path).forward(request, response);
        }
    }

    private void returnData(HttpServletResponse response, Data data) throws IOException {

        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        try (PrintWriter printWriter = response.getWriter()) {
            printWriter.write(JsonUtils.toJson(data.getModel()));
        } catch (IOException e) {
            throw e;
        }
    }
}
